package clientsession

import (
	"context"
	"net"
	"src/iinf"
	"src/log"
)

// ClientSession ClientSession
type ClientSession struct {
	iinf.SessionBase
	status     string
	id         int
	connServer net.Conn
	connSSH    net.Conn
	maxBufLen  int
	cancelFunc context.CancelFunc
}

func (c *ClientSession) setQuit() {
	c.status = "quit"
}

func (c *ClientSession) goServer2Proxy(ctx context.Context) {
	defer c.setQuit()

	data := make([]byte, c.maxBufLen)
	for {
		select {
		case <-ctx.Done():
			log.Println("goServer2Proxy ctx notify exit")
			return
		default:
			n, err := c.connServer.Read(data[0:])
			if err != nil {
				log.Println(err)
				return
			}
			n, err = c.connSSH.Write(data[0:n])
			if err != nil {
				log.Println(err)
				return
			}
		}
	}
}

func (c *ClientSession) goProxy2Server(ctx context.Context) {
	defer c.setQuit()

	data := make([]byte, c.maxBufLen)
	for {
		select {
		case <-ctx.Done():
			log.Println("goProxy2Server ctx notify exit")
			return
		default:
			n, err := c.connSSH.Read(data[0:])
			if err != nil {
				log.Println(err)
				return
			}
			n, err = c.connServer.Write(data[0:n])
			if err != nil {
				log.Println(err)
				return
			}
		}
	}
}

//Init 初始化
func (c *ClientSession) Init(args ...interface{}) bool {
	//开两个协程做中转
	ctx, cf := context.WithCancel(context.Background())
	c.cancelFunc = cf
	go c.goServer2Proxy(ctx)
	go c.goProxy2Server(ctx)

	c.status = "running"

	return true
}

//IsQuit 会话是否退出
func (c *ClientSession) IsQuit() bool {
	if c.status == "quit" {
		return true
	}

	return false
}

//Close 关闭会话释放资源等
func (c *ClientSession) Close() {
	c.cancelFunc()
	c.cancelFunc = nil
	if c.connServer != nil {
		c.connServer.Close()
		c.connServer = nil
	}

	if c.connSSH != nil {
		c.connSSH.Close()
		c.connSSH = nil
	}
}

//GetID GetID
func (c *ClientSession) GetID() int {
	return c.id
}

//Show 显示会话数据
func (c *ClientSession) Show() {
	log.Println("id=", c.id,
		"status=", c.status,
		"connServer=", c.connServer.LocalAddr().String(),
		"connSSH=", c.connSSH.LocalAddr().String())
}

//GetNewClientSession 返回一个新的客户端会话
func GetNewClientSession(id int, server, ssh net.Conn, maxBufLen int) *ClientSession {
	return &ClientSession{
		status:     "idle",
		id:         id,
		connServer: server,
		connSSH:    ssh,
		maxBufLen:  maxBufLen,
	}
}
